package com.manager.user.utils;

import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

public class CodeGenerator {
    // 使用 AtomicInteger 保证原子性，初始值设为 1000 以生成4位流水号
    private static final AtomicInteger COUNTER = new AtomicInteger(1000);
    // 随机数生成器
    private static final Random RANDOM = new Random();
    // 上一次生成订单号的时间戳
    private static long lastTimestamp = 0;

    /**
     * 生成唯一的订单编号
     * 格式: ORD + 年月日时分秒 + 4位流水号 + 2位随机数 + 1位校验码
     */
    public static synchronized String generateOrderNumber(String code) {
        long currentTimestamp = System.currentTimeMillis();

        // 处理时钟回拨问题
        if (currentTimestamp < lastTimestamp) {
            throw new RuntimeException("系统时钟回拨，拒绝生成订单号 " + (lastTimestamp - currentTimestamp) + " 毫秒");
        }
        // 如果时间戳相同，则递增计数器；否则重置计数器
        if (currentTimestamp == lastTimestamp) {
            int counterValue = COUNTER.incrementAndGet();
            // 同一毫秒内生成的订单数超过9999时等待下一毫秒
            if (counterValue > 9999) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return "";
            }
        } else {
            lastTimestamp = currentTimestamp;
            COUNTER.set(1000); // 重置计数器
        }

        // 获取4位流水号
        String counterPart = String.valueOf(COUNTER.get());
        // 生成2位随机数
        String randomPart = String.format("%02d", RANDOM.nextInt(100));
        // 组合各部分
        String rawOrderNumber = counterPart + randomPart;
        // 生成校验码
        char checkDigit = generateCheckDigit(rawOrderNumber);

        return code + rawOrderNumber + checkDigit;
    }

    /**
     * 生成校验码（简单的 Luhn 算法变种）
     */
    private static char generateCheckDigit(String rawOrderNumber) {
        int sum = 0;
        for (int i = 0; i < rawOrderNumber.length(); i++) {
            char c = rawOrderNumber.charAt(i);
            if (Character.isDigit(c)) {
                int digit = Character.getNumericValue(c);
                sum += digit;
            } else {
                sum += c;
            }
        }
        return (char) ((sum % 10) + '0');
    }
}
